<!DOCTYPE html>



  


<html class="theme-next pisces use-motion" lang="zh-Hans">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
















  
  
  <link href="/Liang34/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />







<link href="/Liang34/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/Liang34/css/main.css?v=5.1.4" rel="stylesheet" type="text/css" />


  <link rel="apple-touch-icon" sizes="180x180" href="/Liang34/images/apple-touch-icon-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="32x32" href="/Liang34/images/favicon-32x32-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="16x16" href="/Liang34/images/favicon-16x16-next.png?v=5.1.4">


  <link rel="mask-icon" href="/Liang34/images/logo.svg?v=5.1.4" color="#222">





  <meta name="keywords" content="Hexo, NexT" />










<meta name="description" content="PromiseCan you write a promise? Yes,I proimseWhat is promise?在了解promise前，我们先了解一些基本概念：01.区别函数对象与实例对象 1.实例对象：new函数产生的对象，称为实例对象，简称对象 2.函数对象：将函数作为对象使用时，简称函数对 02.两种回调函数 1.同步回调：立即执行，不会放入回调队列中，例如：数组遍历相关的回调函数">
<meta property="og:type" content="article">
<meta property="og:title" content="Promise">
<meta property="og:url" content="https://liang34.github.io/Liang34/2020/03/08/Promise/index.html">
<meta property="og:site_name" content="liang34">
<meta property="og:description" content="PromiseCan you write a promise? Yes,I proimseWhat is promise?在了解promise前，我们先了解一些基本概念：01.区别函数对象与实例对象 1.实例对象：new函数产生的对象，称为实例对象，简称对象 2.函数对象：将函数作为对象使用时，简称函数对 02.两种回调函数 1.同步回调：立即执行，不会放入回调队列中，例如：数组遍历相关的回调函数">
<meta property="article:published_time" content="2020-03-08T13:01:49.000Z">
<meta property="article:modified_time" content="2020-03-09T09:44:03.686Z">
<meta property="article:author" content="LiangJH">
<meta name="twitter:card" content="summary">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/Liang34/',
    scheme: 'Pisces',
    version: '5.1.4',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="https://liang34.github.io/Liang34/2020/03/08/Promise/"/>





  <title>Promise | liang34</title>
  








<meta name="generator" content="Hexo 4.2.0"></head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/Liang34/"  class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">liang34</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle"></p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/Liang34/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/Liang34/tags/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-tags"></i> <br />
            
            标签
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/Liang34/categories/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br />
            
            分类
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/Liang34/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            归档
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="https://liang34.github.io/Liang34/Liang34/2020/03/08/Promise/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="LiangJH">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/Liang34/images/avatar.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="liang34">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">Promise</h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2020-03-08T21:01:49+08:00">
                2020-03-08
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/Liang34/categories/JavaScript/" itemprop="url" rel="index">
                    <span itemprop="name">JavaScript</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <h2 id="Promise"><a href="#Promise" class="headerlink" title="Promise"></a>Promise</h2><h3 id="Can-you-write-a-promise-Yes-I-proimse"><a href="#Can-you-write-a-promise-Yes-I-proimse" class="headerlink" title="Can you write a promise? Yes,I proimse"></a>Can you write a promise? Yes,I proimse</h3><h3 id="What-is-promise"><a href="#What-is-promise" class="headerlink" title="What is promise?"></a>What is promise?</h3><h4 id="在了解promise前，我们先了解一些基本概念："><a href="#在了解promise前，我们先了解一些基本概念：" class="headerlink" title="在了解promise前，我们先了解一些基本概念："></a>在了解promise前，我们先了解一些基本概念：</h4><h3>01.区别函数对象与实例对象</h3>
1.实例对象：new函数产生的对象，称为实例对象，简称对象<br/>
2.函数对象：将函数作为对象使用时，简称函数对
<h3>02.两种回调函数</h3>
1.同步回调：立即执行，不会放入回调队列中，例如：数组遍历相关的回调函数/<b>Promise的excutor函数</b><br/>
2.异步回调：不会立即执行，会放入回调队列中来执行，例如：定时器回调/ajax回调/Promise的成功|失败回调
<h3 style="color:red">03.JS的error处理<h3>
<h4><b>part1.错误的类型</b></h4>
1.Error:所有错误的父类型<br/>
2.ReferError:引用的变量不存在<br/>
3.TypeError:数据类型不正确的错误<br/>
4.RangeError:数据值不在其所允许的范围内，<i>例如var a=new Array(-1)</i><br/>
5.SyntaxError:语法错误<br/>
<h4><b>part2.错误处理</b></h4>
1.捕获错误：try...catch<br/>
2.抛出错误：throw error

<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">handle</span>(<span class="params"></span>) </span>&#123; </span><br><span class="line">    <span class="keyword">if</span> (<span class="built_in">Date</span>.now()%<span class="number">2</span>===<span class="number">0</span>) &#123; </span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'时间为偶数, 不能处理逻辑'</span>) </span><br><span class="line">        &#125; </span><br><span class="line">    <span class="keyword">else</span> &#123; </span><br><span class="line">            <span class="built_in">console</span>.log(<span class="string">'时间为奇数, 可以处理逻辑'</span>) </span><br><span class="line">        &#125; </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">try</span> &#123; </span><br><span class="line">            handle() </span><br><span class="line">        &#125; </span><br><span class="line">    <span class="keyword">catch</span>(error) &#123; <span class="comment">// 捕获错误, 做相应的提示 </span></span><br><span class="line">            alert(<span class="string">'执行出错: '</span> + error.message) </span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<h4><b>part3.error对象的结构</b></h4>
1.message属性：错误的相关信息<br/>
2.stack属性：函数调用栈记录信息

<hr>
<h1>Promise的理解与使用</h2>

<h3 id="1-抽象表达："><a href="#1-抽象表达：" class="headerlink" title="1.抽象表达："></a>1.抽象表达：</h3><p>Promise是js中进行异步编程的新的解决方案（避免了以往的纯异步嵌套回调）<br/></p>
<h3 id="2-具体表达："><a href="#2-具体表达：" class="headerlink" title="2.具体表达："></a>2.具体表达：</h3><p>(1) 从语法上来说：Promise是一个构造函数<br/><br>(2) 从功能上来说：Promise对象用来封装一个异步操作并可以获取其结果<br/></p>
<h3 id="promise的状态"><a href="#promise的状态" class="headerlink" title="promise的状态"></a>promise的状态</h3><p>1.pending(等待状态)<br/><br>2.resolved(解决状态)<br/><br>3.rejected(拒接状态)<br/><br><b>其中转变只可由:<br/><br>1.pending转为resolved<br/><br>2.pending转为rejected<br/><br>且一个promise只可转变一次<br></b></p>
<h3 id="Promise的基本使用"><a href="#Promise的基本使用" class="headerlink" title="Promise的基本使用"></a>Promise的基本使用</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//创建Promise对象</span></span><br><span class="line"><span class="keyword">const</span> p=<span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve,reject</span>)=&gt;</span>&#123;</span><br><span class="line">    <span class="comment">//执行异步操作</span></span><br><span class="line">    setTimeout(<span class="function"><span class="params">()</span>=&gt;</span>&#123;</span><br><span class="line">        resolve(<span class="string">"成功了"</span>)<span class="comment">//成功时调用</span></span><br><span class="line">        <span class="comment">//reject("失败了")//失败是调用</span></span><br><span class="line">    &#125;)</span><br><span class="line">&#125;)</span><br><span class="line"><span class="comment">//通过promise的then()指定成功和失败的回调函数</span></span><br><span class="line">p.then(</span><br><span class="line">    value =&gt; <span class="built_in">console</span>.log(value),<span class="comment">//成功了</span></span><br><span class="line">    reason =&gt; <span class="built_in">console</span>.log(reason)<span class="comment">//失败了</span></span><br><span class="line">)</span><br></pre></td></tr></table></figure>
<h3 id="为什么要用Promise"><a href="#为什么要用Promise" class="headerlink" title="为什么要用Promise"></a>为什么要用Promise</h3><h4 id="1-指定回调函数的方式更灵活"><a href="#1-指定回调函数的方式更灵活" class="headerlink" title="1.指定回调函数的方式更灵活"></a>1.指定回调函数的方式更灵活</h4><p>传统必须在启动任务前指定回调<br/><br>而promise先启动异步任务=&gt;返回promise对象=&gt;给promise对象绑定回调函数(甚至可以在异步任务结束后指定)</p>
<h4 id="2-支持链式调用，可以解决回调地狱问题"><a href="#2-支持链式调用，可以解决回调地狱问题" class="headerlink" title="2.支持链式调用，可以解决回调地狱问题"></a>2.支持链式调用，可以解决回调地狱问题</h4><p>回调地狱：回调函数嵌套调用，外部回调函数异步执行的结果是嵌套的回调执行的条件，这样就造成不便于阅读、不便于异常处理<br>promise所支持的链式调用可以解决这个方案</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//成功的回调</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">successCallback</span>(<span class="params">result</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">"成功了"</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//失败的回调</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">failureCallback</span>(<span class="params">error</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">"失败了"</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//使用纯回调函数</span></span><br><span class="line">createAudioFileAsync(audio,successCallback,failureCallback)</span><br><span class="line"><span class="comment">/* 1.2. 使用 Promise */</span></span><br><span class="line"><span class="keyword">const</span> promise = createAudioFileAsync(audio);</span><br><span class="line">    setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123; </span><br><span class="line">        promise.then(successCallback, failureCallback); </span><br><span class="line">    &#125;, <span class="number">3000</span>)</span><br><span class="line"><span class="comment">//回调地狱</span></span><br><span class="line"> doSomething(<span class="function"><span class="keyword">function</span>(<span class="params">result</span>) </span>&#123; </span><br><span class="line">     doSomethingElse(result, <span class="function"><span class="keyword">function</span>(<span class="params">newResult</span>) </span>&#123;</span><br><span class="line">         doThirdThing(newResult, <span class="function"><span class="keyword">function</span>(<span class="params">finalResult</span>) </span>&#123;</span><br><span class="line">             <span class="built_in">console</span>.log(<span class="string">'Got the final result: '</span> + finalResult) </span><br><span class="line">             &#125;, failureCallback) </span><br><span class="line">            &#125;, failureCallback) </span><br><span class="line">        &#125;, failureCallback)</span><br><span class="line"> <span class="comment">/* </span></span><br><span class="line"><span class="comment">2.2. 使用promise的链式调用解决回调地狱</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">doSomething()</span><br><span class="line">.then(<span class="function"><span class="keyword">function</span>(<span class="params">result</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> doSomethingElse(result)</span><br><span class="line">&#125;)</span><br><span class="line">.then(<span class="function"><span class="keyword">function</span>(<span class="params">newResult</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> doThirdThing(newResult)</span><br><span class="line">&#125;)</span><br><span class="line">.then(<span class="function"><span class="keyword">function</span>(<span class="params">finalResult</span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">'Got the final result: '</span> + finalResult)</span><br><span class="line">&#125;)</span><br><span class="line">.catch(failureCallback)</span><br><span class="line"><span class="comment">/* </span></span><br><span class="line"><span class="comment">2.3. async/await: 回调地狱的终极解决方案</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">request</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> result = <span class="keyword">await</span> doSomething()</span><br><span class="line">    <span class="keyword">const</span> newResult = <span class="keyword">await</span> doSomethingElse(result)</span><br><span class="line">    <span class="keyword">const</span> finalResult = <span class="keyword">await</span> doThirdThing(newResult)</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'Got the final result: '</span> + finalResult)</span><br><span class="line">  &#125; <span class="keyword">catch</span> (error) &#123;</span><br><span class="line">    failureCallback(error)</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>
<h3 id="PromiseAPI"><a href="#PromiseAPI" class="headerlink" title="PromiseAPI"></a>PromiseAPI</h3><pre><code>1. Promise构造函数: Promise (excutor) {}
    excutor函数: 同步执行  (resolve, reject) =&gt; {}
    resolve函数: 内部定义成功时我们调用的函数 value =&gt; {}
    reject函数: 内部定义失败时我们调用的函数 reason =&gt; {}
    说明: excutor会在Promise内部立即同步回调,异步操作在执行器中执行

2. Promise.prototype.then方法: (onResolved, onRejected) =&gt; {}
    onResolved函数: 成功的回调函数  (value) =&gt; {}
    onRejected函数: 失败的回调函数 (reason) =&gt; {}
    说明: 指定用于得到成功value的成功回调和用于得到失败reason的失败回调
          返回一个新的promise对象

3. Promise.prototype.catch方法: (onRejected) =&gt; {}
    onRejected函数: 失败的回调函数 (reason) =&gt; {}
    说明: then()的语法糖, 相当于: then(undefined, onRejected)

4. Promise.resolve方法: (value) =&gt; {}
    value: 成功的数据或promise对象
    说明: 返回一个成功/失败的promise对象

5. Promise.reject方法: (reason) =&gt; {}
    reason: 失败的原因
    说明: 返回一个失败的promise对象

6. Promise.all方法: (promises) =&gt; {}
    promises: 包含n个promise的数组
    说明: 返回一个新的promise, 只有所有的promise都成功才成功, 只要有一个失败了就直接失败
7. Promise.race方法: (promises) =&gt; {}
    promises: 包含n个promise的数组
    说明: 返回一个新的promise, 第一个完成的promise的结果状态就是最终的结果状态</code></pre><h3 id="Promise的相关问题"><a href="#Promise的相关问题" class="headerlink" title="Promise的相关问题"></a>Promise的相关问题</h3><pre><code>1.如何改变promise的状态?
  (1)resolve(value): 如果当前是pendding就会变为resolved
  (2)reject(reason): 如果当前是pendding就会变为rejected
  (3)抛出异常: 如果当前是pendding就会变为rejected

2.    一个promise指定多个成功/失败回调函数, 都会调用吗?
  当promise改变为对应状态时都会调用</code></pre><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> p=<span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve,reject</span>)=&gt;</span>&#123;</span><br><span class="line">    resolve(<span class="number">1</span>)</span><br><span class="line">    <span class="comment">//theow 3</span></span><br><span class="line">&#125;)</span><br><span class="line"><span class="comment">//下面这两个then均会调用</span></span><br><span class="line"> p.then(</span><br><span class="line">      value =&gt; &#123;&#125;,</span><br><span class="line">      reason =&gt; &#123;<span class="built_in">console</span>.log(<span class="string">'reason'</span>, reason)&#125;</span><br><span class="line">    )</span><br><span class="line">p.then(</span><br><span class="line">      value =&gt; &#123;&#125;,</span><br><span class="line">      reason =&gt; &#123;<span class="built_in">console</span>.log(<span class="string">'reason2'</span>, reason)&#125;</span><br><span class="line">    )</span><br></pre></td></tr></table></figure>
<pre><code> 3.改变promise状态和指定回调函数谁先谁后?
  (1)都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
  (2)如何先改状态再指定回调?
    ①在执行器中直接调用resolve()/reject()
    ②延迟更长时间才调用then()
  (3)什么时候才能得到数据?
    ①如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
    ②如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据

4.promise.then()返回的新promise的结果状态由什么决定?
  (1)简单表达: 由then()指定的回调函数执行的结果决定
  (2)详细表达:
      ①如果抛出异常, 新promise变为rejected, reason为抛出的异常
      ②如果返回的是非promise的任意值, 新promise变为resolved, value为返回的值
      ③如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果 
5.promise如何串连多个操作任务?
  (1)promise的then()返回一个新的promise, 可以开成then()的链式调用
  (2)通过then的链式调用串连多个同步/异步任务
6.promise异常传/穿透?
  (1)当使用promise的then链式调用时, 可以在最后指定失败的回调, 
  (2)前面任何操作出了异常, 都会传到最后失败的回调中处理
7.中断promise链?
  (1)当使用promise的then链式调用时, 在中间中断, 不再调用后面的回调函数
  (2)办法: 在回调函数中返回一个pendding状态的promise对象
    new Promise(() =&gt; {}) 返回一个pending的promise  中断promise链</code></pre><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* </span></span><br><span class="line"><span class="comment">自定义Promise函数模块: IIFE</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">(<span class="function"><span class="keyword">function</span> (<span class="params">window</span>) </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> PENDING = <span class="string">'pending'</span></span><br><span class="line">  <span class="keyword">const</span> RESOLVED = <span class="string">'resolved'</span></span><br><span class="line">  <span class="keyword">const</span> REJECTED = <span class="string">'rejected'</span></span><br><span class="line">  </span><br><span class="line">  <span class="comment">/* </span></span><br><span class="line"><span class="comment">  Promise构造函数</span></span><br><span class="line"><span class="comment">  excutor: 执行器函数(同步执行)</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line">  <span class="function"><span class="keyword">function</span> <span class="title">Promise</span>(<span class="params">excutor</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// 将当前promise对象保存起来</span></span><br><span class="line">    <span class="keyword">const</span> self = <span class="keyword">this</span></span><br><span class="line">    self.status = PENDING <span class="comment">// 给promise对象指定status属性, 初始值为pending</span></span><br><span class="line">    self.data = <span class="literal">undefined</span> <span class="comment">// 给promise对象指定一个用于存储结果数据的属性</span></span><br><span class="line">    self.callbacks = [] <span class="comment">// 每个元素的结构: &#123; onResolved() &#123;&#125;, onRejected() &#123;&#125;&#125;</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">resolve</span> (<span class="params">value</span>) </span>&#123;</span><br><span class="line">      <span class="comment">// 如果当前状态不是pending, 直接结束</span></span><br><span class="line">      <span class="keyword">if</span> (self.status!==PENDING) &#123;</span><br><span class="line">        <span class="keyword">return</span></span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="comment">// 将状态改为resolved</span></span><br><span class="line">      self.status = RESOLVED</span><br><span class="line">      <span class="comment">// 保存value数据</span></span><br><span class="line">      self.data = value</span><br><span class="line">      <span class="comment">// 如果有待执行callback函数, 立即异步执行回调函数onResolved</span></span><br><span class="line">      <span class="keyword">if</span> (self.callbacks.length&gt;<span class="number">0</span>) &#123;</span><br><span class="line">        setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123; <span class="comment">// 放入队列中执行所有成功的回调</span></span><br><span class="line">          self.callbacks.forEach(<span class="function"><span class="params">calbacksObj</span> =&gt;</span> &#123;</span><br><span class="line">            calbacksObj.onResolved(value)</span><br><span class="line">          &#125;) </span><br><span class="line">        &#125;);</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">reject</span> (<span class="params">reason</span>) </span>&#123;</span><br><span class="line">      <span class="comment">// 如果当前状态不是pending, 直接结束</span></span><br><span class="line">      <span class="keyword">if</span> (self.status!==PENDING) &#123;</span><br><span class="line">        <span class="keyword">return</span></span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="comment">// 将状态改为rejected</span></span><br><span class="line">      self.status = REJECTED</span><br><span class="line">      <span class="comment">// 保存value数据</span></span><br><span class="line">      self.data = reason</span><br><span class="line">      <span class="comment">// 如果有待执行callback函数, 立即异步执行回调函数onRejected</span></span><br><span class="line">      <span class="keyword">if</span> (self.callbacks.length&gt;<span class="number">0</span>) &#123;</span><br><span class="line">        setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123; <span class="comment">// 放入队列中执行所有成功的回调</span></span><br><span class="line">          self.callbacks.forEach(<span class="function"><span class="params">calbacksObj</span> =&gt;</span> &#123;</span><br><span class="line">            calbacksObj.onRejected(reason)</span><br><span class="line">          &#125;) </span><br><span class="line">        &#125;);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 立即同步执行excutor</span></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      excutor(resolve, reject)</span><br><span class="line">    &#125; <span class="keyword">catch</span> (error) &#123; <span class="comment">// 如果执行器抛出异常, promise对象变为rejected状态</span></span><br><span class="line">      reject(error)</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* </span></span><br><span class="line"><span class="comment">  Promise原型对象的then()</span></span><br><span class="line"><span class="comment">  指定成功和失败的回调函数</span></span><br><span class="line"><span class="comment">  返回一个新的promise对象</span></span><br><span class="line"><span class="comment">  返回promise的结果由onResolved/onRejected执行结果决定</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line">  <span class="built_in">Promise</span>.prototype.then = <span class="function"><span class="keyword">function</span> (<span class="params">onResolved, onRejected</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">const</span> self = <span class="keyword">this</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 指定回调函数的默认值(必须是函数)</span></span><br><span class="line">    onResolved = <span class="keyword">typeof</span> onResolved===<span class="string">'function'</span> ? onResolved : <span class="function"><span class="params">value</span> =&gt;</span> value</span><br><span class="line">    onRejected = <span class="keyword">typeof</span> onRejected===<span class="string">'function'</span> ? onRejected : <span class="function"><span class="params">reason</span> =&gt;</span> &#123;<span class="keyword">throw</span> reason&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 返回一个新的promise</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line"></span><br><span class="line">      <span class="comment">/* </span></span><br><span class="line"><span class="comment">      执行指定的回调函数</span></span><br><span class="line"><span class="comment">      根据执行的结果改变return的promise的状态/数据</span></span><br><span class="line"><span class="comment">      */</span></span><br><span class="line">      <span class="function"><span class="keyword">function</span> <span class="title">handle</span>(<span class="params">callback</span>) </span>&#123;</span><br><span class="line">        <span class="comment">/* </span></span><br><span class="line"><span class="comment">        返回promise的结果由onResolved/onRejected执行结果决定</span></span><br><span class="line"><span class="comment">        1. 抛出异常, 返回promise的结果为失败, reason为异常</span></span><br><span class="line"><span class="comment">        2. 返回的是promise, 返回promise的结果就是这个结果</span></span><br><span class="line"><span class="comment">        3. 返回的不是promise, 返回promise为成功, value就是返回值</span></span><br><span class="line"><span class="comment">        */</span></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">          <span class="keyword">const</span> result = callback(self.data)</span><br><span class="line">          <span class="keyword">if</span> (result <span class="keyword">instanceof</span> <span class="built_in">Promise</span>) &#123; <span class="comment">// 2. 返回的是promise, 返回promise的结果就是这个结果</span></span><br><span class="line">            <span class="comment">/* </span></span><br><span class="line"><span class="comment">            result.then(</span></span><br><span class="line"><span class="comment">              value =&gt; resolve(vlaue),</span></span><br><span class="line"><span class="comment">              reason =&gt; reject(reason)</span></span><br><span class="line"><span class="comment">            ) */</span></span><br><span class="line">            result.then(resolve, reject)</span><br><span class="line">          &#125; <span class="keyword">else</span> &#123; <span class="comment">// 3. 返回的不是promise, 返回promise为成功, value就是返回值</span></span><br><span class="line">            resolve(result)</span><br><span class="line">          &#125;</span><br><span class="line"></span><br><span class="line">        &#125; <span class="keyword">catch</span> (error) &#123; <span class="comment">// 1. 抛出异常, 返回promise的结果为失败, reason为异常</span></span><br><span class="line">          reject(error)</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="comment">// 当前promise的状态是resolved</span></span><br><span class="line">      <span class="keyword">if</span> (self.status===RESOLVED) &#123;</span><br><span class="line">        <span class="comment">// 立即异步执行成功的回调函数</span></span><br><span class="line">        setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">          handle(onResolved)</span><br><span class="line">        &#125;)</span><br><span class="line">      &#125; <span class="keyword">else</span> <span class="keyword">if</span> (self.status===REJECTED) &#123; <span class="comment">// 当前promise的状态是rejected</span></span><br><span class="line">        <span class="comment">// 立即异步执行失败的回调函数</span></span><br><span class="line">        setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">          handle(onRejected)</span><br><span class="line">        &#125;)</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123; <span class="comment">// 当前promise的状态是pending</span></span><br><span class="line">        <span class="comment">// 将成功和失败的回调函数保存callbacks容器中缓存起来</span></span><br><span class="line">        self.callbacks.push(&#123;</span><br><span class="line">          onResolved (value) &#123;</span><br><span class="line">            handle(onResolved)</span><br><span class="line">          &#125;,</span><br><span class="line">          onRejected (reason) &#123;</span><br><span class="line">            handle(onRejected)</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line"><span class="comment">/* </span></span><br><span class="line"><span class="comment">  function fn(event) &#123;</span></span><br><span class="line"><span class="comment">    </span></span><br><span class="line"><span class="comment">  &#125;</span></span><br><span class="line"><span class="comment">  div.onclick = function (event)&#123;</span></span><br><span class="line"><span class="comment">    fn(event)</span></span><br><span class="line"><span class="comment">  &#125;</span></span><br><span class="line"><span class="comment">  div.onclick = fn</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">  <span class="comment">/* </span></span><br><span class="line"><span class="comment">  Promise原型对象的catch()</span></span><br><span class="line"><span class="comment">  指定失败的回调函数</span></span><br><span class="line"><span class="comment">  返回一个新的promise对象</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line">  <span class="built_in">Promise</span>.prototype.catch = <span class="function"><span class="keyword">function</span> (<span class="params">onRejected</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">this</span>.then(<span class="literal">undefined</span>, onRejected)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* </span></span><br><span class="line"><span class="comment">  Promise函数对象的resolve方法</span></span><br><span class="line"><span class="comment">  返回一个指定结果的成功的promise</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line">  <span class="built_in">Promise</span>.resolve = <span class="function"><span class="keyword">function</span> (<span class="params">value</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// 返回一个成功/失败的promise</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="comment">// value是promise</span></span><br><span class="line">      <span class="keyword">if</span> (value <span class="keyword">instanceof</span> <span class="built_in">Promise</span>) &#123; <span class="comment">// 使用value的结果作为promise的结果</span></span><br><span class="line">        value.then(resolve, reject)</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123; <span class="comment">// value不是promise  =&gt; promise变为成功, 数据是value</span></span><br><span class="line">        resolve(value)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* </span></span><br><span class="line"><span class="comment">  Promise函数对象的reject方法</span></span><br><span class="line"><span class="comment">  返回一个指定reason的失败的promise</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line">  <span class="built_in">Promise</span>.reject = <span class="function"><span class="keyword">function</span> (<span class="params">reason</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// 返回一个失败的promise</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">      reject(reason)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* </span></span><br><span class="line"><span class="comment">  Promise函数对象的all方法</span></span><br><span class="line"><span class="comment">  返回一个promise, 只有当所有proimse都成功时才成功, 否则只要有一个失败的就失败</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line">  <span class="built_in">Promise</span>.all = <span class="function"><span class="keyword">function</span> (<span class="params">promises</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// 用来保存所有成功value的数组</span></span><br><span class="line">    <span class="keyword">const</span> values = <span class="keyword">new</span> <span class="built_in">Array</span>(promises.length) </span><br><span class="line">    <span class="comment">// 用来保存成功promise的数量</span></span><br><span class="line">    <span class="keyword">let</span> resolvedCount = <span class="number">0</span></span><br><span class="line">    <span class="comment">// 返回一个新的promise</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="comment">// 遍历promises获取每个promise的结果</span></span><br><span class="line">      promises.forEach(<span class="function">(<span class="params">p, index</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="built_in">Promise</span>.resolve(p).then(</span><br><span class="line">          value =&gt; &#123;</span><br><span class="line">            resolvedCount++ <span class="comment">// 成功的数量加1</span></span><br><span class="line">            <span class="comment">// p成功, 将成功的vlaue保存vlaues</span></span><br><span class="line">            <span class="comment">// values.push(value)</span></span><br><span class="line">            values[index] = value</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 如果全部成功了, 将return的promise改变成功</span></span><br><span class="line">            <span class="keyword">if</span> (resolvedCount===promises.length) &#123;</span><br><span class="line">              resolve(values)</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">          &#125;,</span><br><span class="line">          reason =&gt; &#123; <span class="comment">// 只要一个失败了, return的promise就失败</span></span><br><span class="line">            reject(reason)</span><br><span class="line">          &#125;</span><br><span class="line">        )</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* </span></span><br><span class="line"><span class="comment">  Promise函数对象的race方法</span></span><br><span class="line"><span class="comment">  返回一个promise, 其结果由第一个完成的promise决定</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line">  <span class="built_in">Promise</span>.race = <span class="function"><span class="keyword">function</span> (<span class="params">promises</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// 返回一个promise</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="comment">// 遍历promises获取每个promise的结果</span></span><br><span class="line">      promises.forEach(<span class="function">(<span class="params">p, index</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="built_in">Promise</span>.resolve(p).then(</span><br><span class="line">          value =&gt; &#123;<span class="comment">// 一旦有成功了, 将return变为成功</span></span><br><span class="line">            resolve(value)</span><br><span class="line">          &#125;,</span><br><span class="line">          reason =&gt; &#123; <span class="comment">// 一旦有失败了, 将return变为失败</span></span><br><span class="line">            reject(reason)</span><br><span class="line">          &#125;</span><br><span class="line">        )</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* </span></span><br><span class="line"><span class="comment">  返回一个promise对象, 它在指定的时间后才确定结果</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line">  <span class="built_in">Promise</span>.resolveDelay = <span class="function"><span class="keyword">function</span> (<span class="params">value, time</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// 返回一个成功/失败的promise</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">      setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="comment">// value是promise</span></span><br><span class="line">        <span class="keyword">if</span> (value <span class="keyword">instanceof</span> <span class="built_in">Promise</span>) &#123; <span class="comment">// 使用value的结果作为promise的结果</span></span><br><span class="line">          value.then(resolve, reject)</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123; <span class="comment">// value不是promise  =&gt; promise变为成功, 数据是value</span></span><br><span class="line">          resolve(value)</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;, time)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* </span></span><br><span class="line"><span class="comment">  返回一个promise对象, 它在指定的时间后才失败</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line">  <span class="built_in">Promise</span>.rejectDelay = <span class="function"><span class="keyword">function</span> (<span class="params">reason, time</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// 返回一个失败的promise</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">      setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">        reject(reason)</span><br><span class="line">      &#125;, time)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 向外暴露Promise函数</span></span><br><span class="line">  <span class="built_in">window</span>.Promise = <span class="built_in">Promise</span></span><br><span class="line">&#125;)(<span class="built_in">window</span>)</span><br></pre></td></tr></table></figure>

      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/Liang34/2020/03/08/closure/" rel="next" title="closure">
                <i class="fa fa-chevron-left"></i> closure
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/Liang34/2020/03/19/ArrayTraverse/" rel="prev" title="ArrayTraverse">
                ArrayTraverse <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          

  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>	
  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview-wrap">
            站点概览
          </li>
        </ul>
      

      <section class="site-overview-wrap sidebar-panel">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <img class="site-author-image" itemprop="image"
                src="/Liang34/images/avatar.jpg"
                alt="LiangJH" />
            
              <p class="site-author-name" itemprop="name">LiangJH</p>
              <p class="site-description motion-element" itemprop="description">前端,java</p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/Liang34/archives/%7C%7C%20archive">
              
                  <span class="site-state-item-count">7</span>
                  <span class="site-state-item-name">日志</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-categories">
                
                  <span class="site-state-item-count">3</span>
                  <span class="site-state-item-name">分类</span>
                
              </div>
            

            
              
              
              <div class="site-state-item site-state-tags">
                
                  <span class="site-state-item-count">1</span>
                  <span class="site-state-item-name">标签</span>
                
              </div>
            

          </nav>

          

          

          
          

          
          

          

        </div>
      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#Promise"><span class="nav-number">1.</span> <span class="nav-text">Promise</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#Can-you-write-a-promise-Yes-I-proimse"><span class="nav-number">1.1.</span> <span class="nav-text">Can you write a promise? Yes,I proimse</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#What-is-promise"><span class="nav-number">1.2.</span> <span class="nav-text">What is promise?</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#在了解promise前，我们先了解一些基本概念："><span class="nav-number">1.2.1.</span> <span class="nav-text">在了解promise前，我们先了解一些基本概念：</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#null"><span class="nav-number">1.3.</span> <span class="nav-text">01.区别函数对象与实例对象</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#null"><span class="nav-number">1.4.</span> <span class="nav-text">02.两种回调函数</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#null"><span class="nav-number">1.5.</span> <span class="nav-text">03.JS的error处理
part1.错误的类型
1.Error:所有错误的父类型

2.ReferError:引用的变量不存在

3.TypeError:数据类型不正确的错误

4.RangeError:数据值不在其所允许的范围内，例如var a&#x3D;new Array(-1)

5.SyntaxError:语法错误

part2.错误处理
1.捕获错误：try...catch

2.抛出错误：throw error

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function handle() &amp;#123; 
    if (Date.now()%2&#x3D;&#x3D;&#x3D;0) &amp;#123; 
            throw new Error(&#39;时间为偶数, 不能处理逻辑&#39;) 
        &amp;#125; 
    else &amp;#123; 
            console.log(&#39;时间为奇数, 可以处理逻辑&#39;) 
        &amp;#125; 
    &amp;#125;
    try &amp;#123; 
            handle() 
        &amp;#125; 
    catch(error) &amp;#123; &#x2F;&#x2F; 捕获错误, 做相应的提示 
            alert(&#39;执行出错: &#39; + error.message) 
    &amp;#125;


part3.error对象的结构
1.message属性：错误的相关信息

2.stack属性：函数调用栈记录信息


Promise的理解与使用

1.抽象表达：Promise是js中进行异步编程的新的解决方案（避免了以往的纯异步嵌套回调）

2.具体表达：(1) 从语法上来说：Promise是一个构造函数

(2) 从功能上来说：Promise对象用来封装一个异步操作并可以获取其结果

promise的状态1.pending(等待状态)

2.resolved(解决状态)

3.rejected(拒接状态)

其中转变只可由:

1.pending转为resolved

2.pending转为rejected

且一个promise只可转变一次

Promise的基本使用1
2
3
4
5
6
7
8
9
10
11
12
13
&#x2F;&#x2F;创建Promise对象
const p&#x3D;new Promise((resolve,reject)&#x3D;&gt;&amp;#123;
    &#x2F;&#x2F;执行异步操作
    setTimeout(()&#x3D;&gt;&amp;#123;
        resolve(&quot;成功了&quot;)&#x2F;&#x2F;成功时调用
        &#x2F;&#x2F;reject(&quot;失败了&quot;)&#x2F;&#x2F;失败是调用
    &amp;#125;)
&amp;#125;)
&#x2F;&#x2F;通过promise的then()指定成功和失败的回调函数
p.then(
    value &#x3D;&gt; console.log(value),&#x2F;&#x2F;成功了
    reason &#x3D;&gt; console.log(reason)&#x2F;&#x2F;失败了
)

为什么要用Promise1.指定回调函数的方式更灵活传统必须在启动任务前指定回调

而promise先启动异步任务&#x3D;&gt;返回promise对象&#x3D;&gt;给promise对象绑定回调函数(甚至可以在异步任务结束后指定)
2.支持链式调用，可以解决回调地狱问题回调地狱：回调函数嵌套调用，外部回调函数异步执行的结果是嵌套的回调执行的条件，这样就造成不便于阅读、不便于异常处理
promise所支持的链式调用可以解决这个方案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
&#x2F;&#x2F;成功的回调
function successCallback(result) &amp;#123;
    console.log(&quot;成功了&quot;)
&amp;#125;
&#x2F;&#x2F;失败的回调
function failureCallback(error) &amp;#123;
    console.log(&quot;失败了&quot;)
&amp;#125;
&#x2F;&#x2F;使用纯回调函数
createAudioFileAsync(audio,successCallback,failureCallback)
&#x2F;* 1.2. 使用 Promise *&#x2F;
const promise &#x3D; createAudioFileAsync(audio);
    setTimeout(() &#x3D;&gt; &amp;#123; 
        promise.then(successCallback, failureCallback); 
    &amp;#125;, 3000)
&#x2F;&#x2F;回调地狱
 doSomething(function(result) &amp;#123; 
     doSomethingElse(result, function(newResult) &amp;#123;
         doThirdThing(newResult, function(finalResult) &amp;#123;
             console.log(&#39;Got the final result: &#39; + finalResult) 
             &amp;#125;, failureCallback) 
            &amp;#125;, failureCallback) 
        &amp;#125;, failureCallback)
 &#x2F;* 
2.2. 使用promise的链式调用解决回调地狱
*&#x2F;
doSomething()
.then(function(result) &amp;#123;
  return doSomethingElse(result)
&amp;#125;)
.then(function(newResult) &amp;#123;
  return doThirdThing(newResult)
&amp;#125;)
.then(function(finalResult) &amp;#123;
  console.log(&#39;Got the final result: &#39; + finalResult)
&amp;#125;)
.catch(failureCallback)
&#x2F;* 
2.3. async&#x2F;await: 回调地狱的终极解决方案
*&#x2F;
async function request() &amp;#123;
  try &amp;#123;
    const result &#x3D; await doSomething()
    const newResult &#x3D; await doSomethingElse(result)
    const finalResult &#x3D; await doThirdThing(newResult)
    console.log(&#39;Got the final result: &#39; + finalResult)
  &amp;#125; catch (error) &amp;#123;
    failureCallback(error)
  &amp;#125;

PromiseAPI1. Promise构造函数: Promise (excutor) {}
    excutor函数: 同步执行  (resolve, reject) &#x3D;&gt; {}
    resolve函数: 内部定义成功时我们调用的函数 value &#x3D;&gt; {}
    reject函数: 内部定义失败时我们调用的函数 reason &#x3D;&gt; {}
    说明: excutor会在Promise内部立即同步回调,异步操作在执行器中执行

2. Promise.prototype.then方法: (onResolved, onRejected) &#x3D;&gt; {}
    onResolved函数: 成功的回调函数  (value) &#x3D;&gt; {}
    onRejected函数: 失败的回调函数 (reason) &#x3D;&gt; {}
    说明: 指定用于得到成功value的成功回调和用于得到失败reason的失败回调
          返回一个新的promise对象

3. Promise.prototype.catch方法: (onRejected) &#x3D;&gt; {}
    onRejected函数: 失败的回调函数 (reason) &#x3D;&gt; {}
    说明: then()的语法糖, 相当于: then(undefined, onRejected)

4. Promise.resolve方法: (value) &#x3D;&gt; {}
    value: 成功的数据或promise对象
    说明: 返回一个成功&#x2F;失败的promise对象

5. Promise.reject方法: (reason) &#x3D;&gt; {}
    reason: 失败的原因
    说明: 返回一个失败的promise对象

6. Promise.all方法: (promises) &#x3D;&gt; {}
    promises: 包含n个promise的数组
    说明: 返回一个新的promise, 只有所有的promise都成功才成功, 只要有一个失败了就直接失败
7. Promise.race方法: (promises) &#x3D;&gt; {}
    promises: 包含n个promise的数组
    说明: 返回一个新的promise, 第一个完成的promise的结果状态就是最终的结果状态Promise的相关问题1.如何改变promise的状态?
  (1)resolve(value): 如果当前是pendding就会变为resolved
  (2)reject(reason): 如果当前是pendding就会变为rejected
  (3)抛出异常: 如果当前是pendding就会变为rejected

2.    一个promise指定多个成功&#x2F;失败回调函数, 都会调用吗?
  当promise改变为对应状态时都会调用1
2
3
4
5
6
7
8
9
10
11
12
13
const p&#x3D;new Promise((resolve,reject)&#x3D;&gt;&amp;#123;
    resolve(1)
    &#x2F;&#x2F;theow 3
&amp;#125;)
&#x2F;&#x2F;下面这两个then均会调用
 p.then(
      value &#x3D;&gt; &amp;#123;&amp;#125;,
      reason &#x3D;&gt; &amp;#123;console.log(&#39;reason&#39;, reason)&amp;#125;
    )
p.then(
      value &#x3D;&gt; &amp;#123;&amp;#125;,
      reason &#x3D;&gt; &amp;#123;console.log(&#39;reason2&#39;, reason)&amp;#125;
    )

 3.改变promise状态和指定回调函数谁先谁后?
  (1)都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
  (2)如何先改状态再指定回调?
    ①在执行器中直接调用resolve()&#x2F;reject()
    ②延迟更长时间才调用then()
  (3)什么时候才能得到数据?
    ①如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
    ②如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据

4.promise.then()返回的新promise的结果状态由什么决定?
  (1)简单表达: 由then()指定的回调函数执行的结果决定
  (2)详细表达:
      ①如果抛出异常, 新promise变为rejected, reason为抛出的异常
      ②如果返回的是非promise的任意值, 新promise变为resolved, value为返回的值
      ③如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果 
5.promise如何串连多个操作任务?
  (1)promise的then()返回一个新的promise, 可以开成then()的链式调用
  (2)通过then的链式调用串连多个同步&#x2F;异步任务
6.promise异常传&#x2F;穿透?
  (1)当使用promise的then链式调用时, 可以在最后指定失败的回调, 
  (2)前面任何操作出了异常, 都会传到最后失败的回调中处理
7.中断promise链?
  (1)当使用promise的then链式调用时, 在中间中断, 不再调用后面的回调函数
  (2)办法: 在回调函数中返回一个pendding状态的promise对象
    new Promise(() &#x3D;&gt; {}) 返回一个pending的promise  中断promise链1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
&#x2F;* 
自定义Promise函数模块: IIFE
*&#x2F;
(function (window) &amp;#123;

  const PENDING &#x3D; &#39;pending&#39;
  const RESOLVED &#x3D; &#39;resolved&#39;
  const REJECTED &#x3D; &#39;rejected&#39;
  
  &#x2F;* 
  Promise构造函数
  excutor: 执行器函数(同步执行)
  *&#x2F;
  function Promise(excutor) &amp;#123;
    &#x2F;&#x2F; 将当前promise对象保存起来
    const self &#x3D; this
    self.status &#x3D; PENDING &#x2F;&#x2F; 给promise对象指定status属性, 初始值为pending
    self.data &#x3D; undefined &#x2F;&#x2F; 给promise对象指定一个用于存储结果数据的属性
    self.callbacks &#x3D; [] &#x2F;&#x2F; 每个元素的结构: &amp;#123; onResolved() &amp;#123;&amp;#125;, onRejected() &amp;#123;&amp;#125;&amp;#125;

    function resolve (value) &amp;#123;
      &#x2F;&#x2F; 如果当前状态不是pending, 直接结束
      if (self.status!&#x3D;&#x3D;PENDING) &amp;#123;
        return
      &amp;#125;

      &#x2F;&#x2F; 将状态改为resolved
      self.status &#x3D; RESOLVED
      &#x2F;&#x2F; 保存value数据
      self.data &#x3D; value
      &#x2F;&#x2F; 如果有待执行callback函数, 立即异步执行回调函数onResolved
      if (self.callbacks.length&gt;0) &amp;#123;
        setTimeout(() &#x3D;&gt; &amp;#123; &#x2F;&#x2F; 放入队列中执行所有成功的回调
          self.callbacks.forEach(calbacksObj &#x3D;&gt; &amp;#123;
            calbacksObj.onResolved(value)
          &amp;#125;) 
        &amp;#125;);
      &amp;#125;

    &amp;#125;

    function reject (reason) &amp;#123;
      &#x2F;&#x2F; 如果当前状态不是pending, 直接结束
      if (self.status!&#x3D;&#x3D;PENDING) &amp;#123;
        return
      &amp;#125;

      &#x2F;&#x2F; 将状态改为rejected
      self.status &#x3D; REJECTED
      &#x2F;&#x2F; 保存value数据
      self.data &#x3D; reason
      &#x2F;&#x2F; 如果有待执行callback函数, 立即异步执行回调函数onRejected
      if (self.callbacks.length&gt;0) &amp;#123;
        setTimeout(() &#x3D;&gt; &amp;#123; &#x2F;&#x2F; 放入队列中执行所有成功的回调
          self.callbacks.forEach(calbacksObj &#x3D;&gt; &amp;#123;
            calbacksObj.onRejected(reason)
          &amp;#125;) 
        &amp;#125;);
      &amp;#125;
    &amp;#125;
    
    &#x2F;&#x2F; 立即同步执行excutor
    try &amp;#123;
      excutor(resolve, reject)
    &amp;#125; catch (error) &amp;#123; &#x2F;&#x2F; 如果执行器抛出异常, promise对象变为rejected状态
      reject(error)
    &amp;#125;
    
  &amp;#125;

  &#x2F;* 
  Promise原型对象的then()
  指定成功和失败的回调函数
  返回一个新的promise对象
  返回promise的结果由onResolved&#x2F;onRejected执行结果决定

  *&#x2F;
  Promise.prototype.then &#x3D; function (onResolved, onRejected) &amp;#123;
    const self &#x3D; this

    &#x2F;&#x2F; 指定回调函数的默认值(必须是函数)
    onResolved &#x3D; typeof onResolved&#x3D;&#x3D;&#x3D;&#39;function&#39; ? onResolved : value &#x3D;&gt; value
    onRejected &#x3D; typeof onRejected&#x3D;&#x3D;&#x3D;&#39;function&#39; ? onRejected : reason &#x3D;&gt; &amp;#123;throw reason&amp;#125;


    &#x2F;&#x2F; 返回一个新的promise
    return new Promise((resolve, reject) &#x3D;&gt; &amp;#123;

      &#x2F;* 
      执行指定的回调函数
      根据执行的结果改变return的promise的状态&#x2F;数据
      *&#x2F;
      function handle(callback) &amp;#123;
        &#x2F;* 
        返回promise的结果由onResolved&#x2F;onRejected执行结果决定
        1. 抛出异常, 返回promise的结果为失败, reason为异常
        2. 返回的是promise, 返回promise的结果就是这个结果
        3. 返回的不是promise, 返回promise为成功, value就是返回值
        *&#x2F;
        try &amp;#123;
          const result &#x3D; callback(self.data)
          if (result instanceof Promise) &amp;#123; &#x2F;&#x2F; 2. 返回的是promise, 返回promise的结果就是这个结果
            &#x2F;* 
            result.then(
              value &#x3D;&gt; resolve(vlaue),
              reason &#x3D;&gt; reject(reason)
            ) *&#x2F;
            result.then(resolve, reject)
          &amp;#125; else &amp;#123; &#x2F;&#x2F; 3. 返回的不是promise, 返回promise为成功, value就是返回值
            resolve(result)
          &amp;#125;

        &amp;#125; catch (error) &amp;#123; &#x2F;&#x2F; 1. 抛出异常, 返回promise的结果为失败, reason为异常
          reject(error)
        &amp;#125;
      &amp;#125;

      &#x2F;&#x2F; 当前promise的状态是resolved
      if (self.status&#x3D;&#x3D;&#x3D;RESOLVED) &amp;#123;
        &#x2F;&#x2F; 立即异步执行成功的回调函数
        setTimeout(() &#x3D;&gt; &amp;#123;
          handle(onResolved)
        &amp;#125;)
      &amp;#125; else if (self.status&#x3D;&#x3D;&#x3D;REJECTED) &amp;#123; &#x2F;&#x2F; 当前promise的状态是rejected
        &#x2F;&#x2F; 立即异步执行失败的回调函数
        setTimeout(() &#x3D;&gt; &amp;#123;
          handle(onRejected)
        &amp;#125;)
      &amp;#125; else &amp;#123; &#x2F;&#x2F; 当前promise的状态是pending
        &#x2F;&#x2F; 将成功和失败的回调函数保存callbacks容器中缓存起来
        self.callbacks.push(&amp;#123;
          onResolved (value) &amp;#123;
            handle(onResolved)
          &amp;#125;,
          onRejected (reason) &amp;#123;
            handle(onRejected)
          &amp;#125;
        &amp;#125;)
      &amp;#125;
    &amp;#125;)
  &amp;#125;
&#x2F;* 
  function fn(event) &amp;#123;
    
  &amp;#125;
  div.onclick &#x3D; function (event)&amp;#123;
    fn(event)
  &amp;#125;
  div.onclick &#x3D; fn
 *&#x2F;
  &#x2F;* 
  Promise原型对象的catch()
  指定失败的回调函数
  返回一个新的promise对象
  *&#x2F;
  Promise.prototype.catch &#x3D; function (onRejected) &amp;#123;
    return this.then(undefined, onRejected)
  &amp;#125;

  &#x2F;* 
  Promise函数对象的resolve方法
  返回一个指定结果的成功的promise
  *&#x2F;
  Promise.resolve &#x3D; function (value) &amp;#123;
    &#x2F;&#x2F; 返回一个成功&#x2F;失败的promise
    return new Promise((resolve, reject) &#x3D;&gt; &amp;#123;
      &#x2F;&#x2F; value是promise
      if (value instanceof Promise) &amp;#123; &#x2F;&#x2F; 使用value的结果作为promise的结果
        value.then(resolve, reject)
      &amp;#125; else &amp;#123; &#x2F;&#x2F; value不是promise  &#x3D;&gt; promise变为成功, 数据是value
        resolve(value)
      &amp;#125;
    &amp;#125;)
  &amp;#125;

  &#x2F;* 
  Promise函数对象的reject方法
  返回一个指定reason的失败的promise
  *&#x2F;
  Promise.reject &#x3D; function (reason) &amp;#123;
    &#x2F;&#x2F; 返回一个失败的promise
    return new Promise((resolve, reject) &#x3D;&gt; &amp;#123;
      reject(reason)
    &amp;#125;)
  &amp;#125;

  &#x2F;* 
  Promise函数对象的all方法
  返回一个promise, 只有当所有proimse都成功时才成功, 否则只要有一个失败的就失败
  *&#x2F;
  Promise.all &#x3D; function (promises) &amp;#123;
    &#x2F;&#x2F; 用来保存所有成功value的数组
    const values &#x3D; new Array(promises.length) 
    &#x2F;&#x2F; 用来保存成功promise的数量
    let resolvedCount &#x3D; 0
    &#x2F;&#x2F; 返回一个新的promise
    return new Promise((resolve, reject) &#x3D;&gt; &amp;#123;
      &#x2F;&#x2F; 遍历promises获取每个promise的结果
      promises.forEach((p, index) &#x3D;&gt; &amp;#123;
        Promise.resolve(p).then(
          value &#x3D;&gt; &amp;#123;
            resolvedCount++ &#x2F;&#x2F; 成功的数量加1
            &#x2F;&#x2F; p成功, 将成功的vlaue保存vlaues
            &#x2F;&#x2F; values.push(value)
            values[index] &#x3D; value

            &#x2F;&#x2F; 如果全部成功了, 将return的promise改变成功
            if (resolvedCount&#x3D;&#x3D;&#x3D;promises.length) &amp;#123;
              resolve(values)
            &amp;#125;

          &amp;#125;,
          reason &#x3D;&gt; &amp;#123; &#x2F;&#x2F; 只要一个失败了, return的promise就失败
            reject(reason)
          &amp;#125;
        )
      &amp;#125;)
    &amp;#125;)
  &amp;#125;

  &#x2F;* 
  Promise函数对象的race方法
  返回一个promise, 其结果由第一个完成的promise决定
  *&#x2F;
  Promise.race &#x3D; function (promises) &amp;#123;
    &#x2F;&#x2F; 返回一个promise
    return new Promise((resolve, reject) &#x3D;&gt; &amp;#123;
      &#x2F;&#x2F; 遍历promises获取每个promise的结果
      promises.forEach((p, index) &#x3D;&gt; &amp;#123;
        Promise.resolve(p).then(
          value &#x3D;&gt; &amp;#123;&#x2F;&#x2F; 一旦有成功了, 将return变为成功
            resolve(value)
          &amp;#125;,
          reason &#x3D;&gt; &amp;#123; &#x2F;&#x2F; 一旦有失败了, 将return变为失败
            reject(reason)
          &amp;#125;
        )
      &amp;#125;)
    &amp;#125;)
  &amp;#125;

  &#x2F;* 
  返回一个promise对象, 它在指定的时间后才确定结果
  *&#x2F;
  Promise.resolveDelay &#x3D; function (value, time) &amp;#123;
    &#x2F;&#x2F; 返回一个成功&#x2F;失败的promise
    return new Promise((resolve, reject) &#x3D;&gt; &amp;#123;
      setTimeout(() &#x3D;&gt; &amp;#123;
        &#x2F;&#x2F; value是promise
        if (value instanceof Promise) &amp;#123; &#x2F;&#x2F; 使用value的结果作为promise的结果
          value.then(resolve, reject)
        &amp;#125; else &amp;#123; &#x2F;&#x2F; value不是promise  &#x3D;&gt; promise变为成功, 数据是value
          resolve(value)
        &amp;#125;
      &amp;#125;, time)
    &amp;#125;)
  &amp;#125;

  &#x2F;* 
  返回一个promise对象, 它在指定的时间后才失败
  *&#x2F;
  Promise.rejectDelay &#x3D; function (reason, time) &amp;#123;
    &#x2F;&#x2F; 返回一个失败的promise
    return new Promise((resolve, reject) &#x3D;&gt; &amp;#123;
      setTimeout(() &#x3D;&gt; &amp;#123;
        reject(reason)
      &amp;#125;, time)
    &amp;#125;)
  &amp;#125;

  &#x2F;&#x2F; 向外暴露Promise函数
  window.Promise &#x3D; Promise
&amp;#125;)(window)

</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#null"><span class="nav-number">1.6.</span> <span class="nav-text">
part1.错误的类型
1.Error:所有错误的父类型

2.ReferError:引用的变量不存在

3.TypeError:数据类型不正确的错误

4.RangeError:数据值不在其所允许的范围内，例如var a&#x3D;new Array(-1)

5.SyntaxError:语法错误

part2.错误处理
1.捕获错误：try...catch

2.抛出错误：throw error

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function handle() &amp;#123; 
    if (Date.now()%2&#x3D;&#x3D;&#x3D;0) &amp;#123; 
            throw new Error(&#39;时间为偶数, 不能处理逻辑&#39;) 
        &amp;#125; 
    else &amp;#123; 
            console.log(&#39;时间为奇数, 可以处理逻辑&#39;) 
        &amp;#125; 
    &amp;#125;
    try &amp;#123; 
            handle() 
        &amp;#125; 
    catch(error) &amp;#123; &#x2F;&#x2F; 捕获错误, 做相应的提示 
            alert(&#39;执行出错: &#39; + error.message) 
    &amp;#125;


part3.error对象的结构
1.message属性：错误的相关信息

2.stack属性：函数调用栈记录信息


Promise的理解与使用

1.抽象表达：Promise是js中进行异步编程的新的解决方案（避免了以往的纯异步嵌套回调）

2.具体表达：(1) 从语法上来说：Promise是一个构造函数

(2) 从功能上来说：Promise对象用来封装一个异步操作并可以获取其结果

promise的状态1.pending(等待状态)

2.resolved(解决状态)

3.rejected(拒接状态)

其中转变只可由:

1.pending转为resolved

2.pending转为rejected

且一个promise只可转变一次

Promise的基本使用1
2
3
4
5
6
7
8
9
10
11
12
13
&#x2F;&#x2F;创建Promise对象
const p&#x3D;new Promise((resolve,reject)&#x3D;&gt;&amp;#123;
    &#x2F;&#x2F;执行异步操作
    setTimeout(()&#x3D;&gt;&amp;#123;
        resolve(&quot;成功了&quot;)&#x2F;&#x2F;成功时调用
        &#x2F;&#x2F;reject(&quot;失败了&quot;)&#x2F;&#x2F;失败是调用
    &amp;#125;)
&amp;#125;)
&#x2F;&#x2F;通过promise的then()指定成功和失败的回调函数
p.then(
    value &#x3D;&gt; console.log(value),&#x2F;&#x2F;成功了
    reason &#x3D;&gt; console.log(reason)&#x2F;&#x2F;失败了
)

为什么要用Promise1.指定回调函数的方式更灵活传统必须在启动任务前指定回调

而promise先启动异步任务&#x3D;&gt;返回promise对象&#x3D;&gt;给promise对象绑定回调函数(甚至可以在异步任务结束后指定)
2.支持链式调用，可以解决回调地狱问题回调地狱：回调函数嵌套调用，外部回调函数异步执行的结果是嵌套的回调执行的条件，这样就造成不便于阅读、不便于异常处理
promise所支持的链式调用可以解决这个方案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
&#x2F;&#x2F;成功的回调
function successCallback(result) &amp;#123;
    console.log(&quot;成功了&quot;)
&amp;#125;
&#x2F;&#x2F;失败的回调
function failureCallback(error) &amp;#123;
    console.log(&quot;失败了&quot;)
&amp;#125;
&#x2F;&#x2F;使用纯回调函数
createAudioFileAsync(audio,successCallback,failureCallback)
&#x2F;* 1.2. 使用 Promise *&#x2F;
const promise &#x3D; createAudioFileAsync(audio);
    setTimeout(() &#x3D;&gt; &amp;#123; 
        promise.then(successCallback, failureCallback); 
    &amp;#125;, 3000)
&#x2F;&#x2F;回调地狱
 doSomething(function(result) &amp;#123; 
     doSomethingElse(result, function(newResult) &amp;#123;
         doThirdThing(newResult, function(finalResult) &amp;#123;
             console.log(&#39;Got the final result: &#39; + finalResult) 
             &amp;#125;, failureCallback) 
            &amp;#125;, failureCallback) 
        &amp;#125;, failureCallback)
 &#x2F;* 
2.2. 使用promise的链式调用解决回调地狱
*&#x2F;
doSomething()
.then(function(result) &amp;#123;
  return doSomethingElse(result)
&amp;#125;)
.then(function(newResult) &amp;#123;
  return doThirdThing(newResult)
&amp;#125;)
.then(function(finalResult) &amp;#123;
  console.log(&#39;Got the final result: &#39; + finalResult)
&amp;#125;)
.catch(failureCallback)
&#x2F;* 
2.3. async&#x2F;await: 回调地狱的终极解决方案
*&#x2F;
async function request() &amp;#123;
  try &amp;#123;
    const result &#x3D; await doSomething()
    const newResult &#x3D; await doSomethingElse(result)
    const finalResult &#x3D; await doThirdThing(newResult)
    console.log(&#39;Got the final result: &#39; + finalResult)
  &amp;#125; catch (error) &amp;#123;
    failureCallback(error)
  &amp;#125;

PromiseAPI1. Promise构造函数: Promise (excutor) {}
    excutor函数: 同步执行  (resolve, reject) &#x3D;&gt; {}
    resolve函数: 内部定义成功时我们调用的函数 value &#x3D;&gt; {}
    reject函数: 内部定义失败时我们调用的函数 reason &#x3D;&gt; {}
    说明: excutor会在Promise内部立即同步回调,异步操作在执行器中执行

2. Promise.prototype.then方法: (onResolved, onRejected) &#x3D;&gt; {}
    onResolved函数: 成功的回调函数  (value) &#x3D;&gt; {}
    onRejected函数: 失败的回调函数 (reason) &#x3D;&gt; {}
    说明: 指定用于得到成功value的成功回调和用于得到失败reason的失败回调
          返回一个新的promise对象

3. Promise.prototype.catch方法: (onRejected) &#x3D;&gt; {}
    onRejected函数: 失败的回调函数 (reason) &#x3D;&gt; {}
    说明: then()的语法糖, 相当于: then(undefined, onRejected)

4. Promise.resolve方法: (value) &#x3D;&gt; {}
    value: 成功的数据或promise对象
    说明: 返回一个成功&#x2F;失败的promise对象

5. Promise.reject方法: (reason) &#x3D;&gt; {}
    reason: 失败的原因
    说明: 返回一个失败的promise对象

6. Promise.all方法: (promises) &#x3D;&gt; {}
    promises: 包含n个promise的数组
    说明: 返回一个新的promise, 只有所有的promise都成功才成功, 只要有一个失败了就直接失败
7. Promise.race方法: (promises) &#x3D;&gt; {}
    promises: 包含n个promise的数组
    说明: 返回一个新的promise, 第一个完成的promise的结果状态就是最终的结果状态Promise的相关问题1.如何改变promise的状态?
  (1)resolve(value): 如果当前是pendding就会变为resolved
  (2)reject(reason): 如果当前是pendding就会变为rejected
  (3)抛出异常: 如果当前是pendding就会变为rejected

2.    一个promise指定多个成功&#x2F;失败回调函数, 都会调用吗?
  当promise改变为对应状态时都会调用1
2
3
4
5
6
7
8
9
10
11
12
13
const p&#x3D;new Promise((resolve,reject)&#x3D;&gt;&amp;#123;
    resolve(1)
    &#x2F;&#x2F;theow 3
&amp;#125;)
&#x2F;&#x2F;下面这两个then均会调用
 p.then(
      value &#x3D;&gt; &amp;#123;&amp;#125;,
      reason &#x3D;&gt; &amp;#123;console.log(&#39;reason&#39;, reason)&amp;#125;
    )
p.then(
      value &#x3D;&gt; &amp;#123;&amp;#125;,
      reason &#x3D;&gt; &amp;#123;console.log(&#39;reason2&#39;, reason)&amp;#125;
    )

 3.改变promise状态和指定回调函数谁先谁后?
  (1)都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
  (2)如何先改状态再指定回调?
    ①在执行器中直接调用resolve()&#x2F;reject()
    ②延迟更长时间才调用then()
  (3)什么时候才能得到数据?
    ①如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
    ②如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据

4.promise.then()返回的新promise的结果状态由什么决定?
  (1)简单表达: 由then()指定的回调函数执行的结果决定
  (2)详细表达:
      ①如果抛出异常, 新promise变为rejected, reason为抛出的异常
      ②如果返回的是非promise的任意值, 新promise变为resolved, value为返回的值
      ③如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果 
5.promise如何串连多个操作任务?
  (1)promise的then()返回一个新的promise, 可以开成then()的链式调用
  (2)通过then的链式调用串连多个同步&#x2F;异步任务
6.promise异常传&#x2F;穿透?
  (1)当使用promise的then链式调用时, 可以在最后指定失败的回调, 
  (2)前面任何操作出了异常, 都会传到最后失败的回调中处理
7.中断promise链?
  (1)当使用promise的then链式调用时, 在中间中断, 不再调用后面的回调函数
  (2)办法: 在回调函数中返回一个pendding状态的promise对象
    new Promise(() &#x3D;&gt; {}) 返回一个pending的promise  中断promise链1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
&#x2F;* 
自定义Promise函数模块: IIFE
*&#x2F;
(function (window) &amp;#123;

  const PENDING &#x3D; &#39;pending&#39;
  const RESOLVED &#x3D; &#39;resolved&#39;
  const REJECTED &#x3D; &#39;rejected&#39;
  
  &#x2F;* 
  Promise构造函数
  excutor: 执行器函数(同步执行)
  *&#x2F;
  function Promise(excutor) &amp;#123;
    &#x2F;&#x2F; 将当前promise对象保存起来
    const self &#x3D; this
    self.status &#x3D; PENDING &#x2F;&#x2F; 给promise对象指定status属性, 初始值为pending
    self.data &#x3D; undefined &#x2F;&#x2F; 给promise对象指定一个用于存储结果数据的属性
    self.callbacks &#x3D; [] &#x2F;&#x2F; 每个元素的结构: &amp;#123; onResolved() &amp;#123;&amp;#125;, onRejected() &amp;#123;&amp;#125;&amp;#125;

    function resolve (value) &amp;#123;
      &#x2F;&#x2F; 如果当前状态不是pending, 直接结束
      if (self.status!&#x3D;&#x3D;PENDING) &amp;#123;
        return
      &amp;#125;

      &#x2F;&#x2F; 将状态改为resolved
      self.status &#x3D; RESOLVED
      &#x2F;&#x2F; 保存value数据
      self.data &#x3D; value
      &#x2F;&#x2F; 如果有待执行callback函数, 立即异步执行回调函数onResolved
      if (self.callbacks.length&gt;0) &amp;#123;
        setTimeout(() &#x3D;&gt; &amp;#123; &#x2F;&#x2F; 放入队列中执行所有成功的回调
          self.callbacks.forEach(calbacksObj &#x3D;&gt; &amp;#123;
            calbacksObj.onResolved(value)
          &amp;#125;) 
        &amp;#125;);
      &amp;#125;

    &amp;#125;

    function reject (reason) &amp;#123;
      &#x2F;&#x2F; 如果当前状态不是pending, 直接结束
      if (self.status!&#x3D;&#x3D;PENDING) &amp;#123;
        return
      &amp;#125;

      &#x2F;&#x2F; 将状态改为rejected
      self.status &#x3D; REJECTED
      &#x2F;&#x2F; 保存value数据
      self.data &#x3D; reason
      &#x2F;&#x2F; 如果有待执行callback函数, 立即异步执行回调函数onRejected
      if (self.callbacks.length&gt;0) &amp;#123;
        setTimeout(() &#x3D;&gt; &amp;#123; &#x2F;&#x2F; 放入队列中执行所有成功的回调
          self.callbacks.forEach(calbacksObj &#x3D;&gt; &amp;#123;
            calbacksObj.onRejected(reason)
          &amp;#125;) 
        &amp;#125;);
      &amp;#125;
    &amp;#125;
    
    &#x2F;&#x2F; 立即同步执行excutor
    try &amp;#123;
      excutor(resolve, reject)
    &amp;#125; catch (error) &amp;#123; &#x2F;&#x2F; 如果执行器抛出异常, promise对象变为rejected状态
      reject(error)
    &amp;#125;
    
  &amp;#125;

  &#x2F;* 
  Promise原型对象的then()
  指定成功和失败的回调函数
  返回一个新的promise对象
  返回promise的结果由onResolved&#x2F;onRejected执行结果决定

  *&#x2F;
  Promise.prototype.then &#x3D; function (onResolved, onRejected) &amp;#123;
    const self &#x3D; this

    &#x2F;&#x2F; 指定回调函数的默认值(必须是函数)
    onResolved &#x3D; typeof onResolved&#x3D;&#x3D;&#x3D;&#39;function&#39; ? onResolved : value &#x3D;&gt; value
    onRejected &#x3D; typeof onRejected&#x3D;&#x3D;&#x3D;&#39;function&#39; ? onRejected : reason &#x3D;&gt; &amp;#123;throw reason&amp;#125;


    &#x2F;&#x2F; 返回一个新的promise
    return new Promise((resolve, reject) &#x3D;&gt; &amp;#123;

      &#x2F;* 
      执行指定的回调函数
      根据执行的结果改变return的promise的状态&#x2F;数据
      *&#x2F;
      function handle(callback) &amp;#123;
        &#x2F;* 
        返回promise的结果由onResolved&#x2F;onRejected执行结果决定
        1. 抛出异常, 返回promise的结果为失败, reason为异常
        2. 返回的是promise, 返回promise的结果就是这个结果
        3. 返回的不是promise, 返回promise为成功, value就是返回值
        *&#x2F;
        try &amp;#123;
          const result &#x3D; callback(self.data)
          if (result instanceof Promise) &amp;#123; &#x2F;&#x2F; 2. 返回的是promise, 返回promise的结果就是这个结果
            &#x2F;* 
            result.then(
              value &#x3D;&gt; resolve(vlaue),
              reason &#x3D;&gt; reject(reason)
            ) *&#x2F;
            result.then(resolve, reject)
          &amp;#125; else &amp;#123; &#x2F;&#x2F; 3. 返回的不是promise, 返回promise为成功, value就是返回值
            resolve(result)
          &amp;#125;

        &amp;#125; catch (error) &amp;#123; &#x2F;&#x2F; 1. 抛出异常, 返回promise的结果为失败, reason为异常
          reject(error)
        &amp;#125;
      &amp;#125;

      &#x2F;&#x2F; 当前promise的状态是resolved
      if (self.status&#x3D;&#x3D;&#x3D;RESOLVED) &amp;#123;
        &#x2F;&#x2F; 立即异步执行成功的回调函数
        setTimeout(() &#x3D;&gt; &amp;#123;
          handle(onResolved)
        &amp;#125;)
      &amp;#125; else if (self.status&#x3D;&#x3D;&#x3D;REJECTED) &amp;#123; &#x2F;&#x2F; 当前promise的状态是rejected
        &#x2F;&#x2F; 立即异步执行失败的回调函数
        setTimeout(() &#x3D;&gt; &amp;#123;
          handle(onRejected)
        &amp;#125;)
      &amp;#125; else &amp;#123; &#x2F;&#x2F; 当前promise的状态是pending
        &#x2F;&#x2F; 将成功和失败的回调函数保存callbacks容器中缓存起来
        self.callbacks.push(&amp;#123;
          onResolved (value) &amp;#123;
            handle(onResolved)
          &amp;#125;,
          onRejected (reason) &amp;#123;
            handle(onRejected)
          &amp;#125;
        &amp;#125;)
      &amp;#125;
    &amp;#125;)
  &amp;#125;
&#x2F;* 
  function fn(event) &amp;#123;
    
  &amp;#125;
  div.onclick &#x3D; function (event)&amp;#123;
    fn(event)
  &amp;#125;
  div.onclick &#x3D; fn
 *&#x2F;
  &#x2F;* 
  Promise原型对象的catch()
  指定失败的回调函数
  返回一个新的promise对象
  *&#x2F;
  Promise.prototype.catch &#x3D; function (onRejected) &amp;#123;
    return this.then(undefined, onRejected)
  &amp;#125;

  &#x2F;* 
  Promise函数对象的resolve方法
  返回一个指定结果的成功的promise
  *&#x2F;
  Promise.resolve &#x3D; function (value) &amp;#123;
    &#x2F;&#x2F; 返回一个成功&#x2F;失败的promise
    return new Promise((resolve, reject) &#x3D;&gt; &amp;#123;
      &#x2F;&#x2F; value是promise
      if (value instanceof Promise) &amp;#123; &#x2F;&#x2F; 使用value的结果作为promise的结果
        value.then(resolve, reject)
      &amp;#125; else &amp;#123; &#x2F;&#x2F; value不是promise  &#x3D;&gt; promise变为成功, 数据是value
        resolve(value)
      &amp;#125;
    &amp;#125;)
  &amp;#125;

  &#x2F;* 
  Promise函数对象的reject方法
  返回一个指定reason的失败的promise
  *&#x2F;
  Promise.reject &#x3D; function (reason) &amp;#123;
    &#x2F;&#x2F; 返回一个失败的promise
    return new Promise((resolve, reject) &#x3D;&gt; &amp;#123;
      reject(reason)
    &amp;#125;)
  &amp;#125;

  &#x2F;* 
  Promise函数对象的all方法
  返回一个promise, 只有当所有proimse都成功时才成功, 否则只要有一个失败的就失败
  *&#x2F;
  Promise.all &#x3D; function (promises) &amp;#123;
    &#x2F;&#x2F; 用来保存所有成功value的数组
    const values &#x3D; new Array(promises.length) 
    &#x2F;&#x2F; 用来保存成功promise的数量
    let resolvedCount &#x3D; 0
    &#x2F;&#x2F; 返回一个新的promise
    return new Promise((resolve, reject) &#x3D;&gt; &amp;#123;
      &#x2F;&#x2F; 遍历promises获取每个promise的结果
      promises.forEach((p, index) &#x3D;&gt; &amp;#123;
        Promise.resolve(p).then(
          value &#x3D;&gt; &amp;#123;
            resolvedCount++ &#x2F;&#x2F; 成功的数量加1
            &#x2F;&#x2F; p成功, 将成功的vlaue保存vlaues
            &#x2F;&#x2F; values.push(value)
            values[index] &#x3D; value

            &#x2F;&#x2F; 如果全部成功了, 将return的promise改变成功
            if (resolvedCount&#x3D;&#x3D;&#x3D;promises.length) &amp;#123;
              resolve(values)
            &amp;#125;

          &amp;#125;,
          reason &#x3D;&gt; &amp;#123; &#x2F;&#x2F; 只要一个失败了, return的promise就失败
            reject(reason)
          &amp;#125;
        )
      &amp;#125;)
    &amp;#125;)
  &amp;#125;

  &#x2F;* 
  Promise函数对象的race方法
  返回一个promise, 其结果由第一个完成的promise决定
  *&#x2F;
  Promise.race &#x3D; function (promises) &amp;#123;
    &#x2F;&#x2F; 返回一个promise
    return new Promise((resolve, reject) &#x3D;&gt; &amp;#123;
      &#x2F;&#x2F; 遍历promises获取每个promise的结果
      promises.forEach((p, index) &#x3D;&gt; &amp;#123;
        Promise.resolve(p).then(
          value &#x3D;&gt; &amp;#123;&#x2F;&#x2F; 一旦有成功了, 将return变为成功
            resolve(value)
          &amp;#125;,
          reason &#x3D;&gt; &amp;#123; &#x2F;&#x2F; 一旦有失败了, 将return变为失败
            reject(reason)
          &amp;#125;
        )
      &amp;#125;)
    &amp;#125;)
  &amp;#125;

  &#x2F;* 
  返回一个promise对象, 它在指定的时间后才确定结果
  *&#x2F;
  Promise.resolveDelay &#x3D; function (value, time) &amp;#123;
    &#x2F;&#x2F; 返回一个成功&#x2F;失败的promise
    return new Promise((resolve, reject) &#x3D;&gt; &amp;#123;
      setTimeout(() &#x3D;&gt; &amp;#123;
        &#x2F;&#x2F; value是promise
        if (value instanceof Promise) &amp;#123; &#x2F;&#x2F; 使用value的结果作为promise的结果
          value.then(resolve, reject)
        &amp;#125; else &amp;#123; &#x2F;&#x2F; value不是promise  &#x3D;&gt; promise变为成功, 数据是value
          resolve(value)
        &amp;#125;
      &amp;#125;, time)
    &amp;#125;)
  &amp;#125;

  &#x2F;* 
  返回一个promise对象, 它在指定的时间后才失败
  *&#x2F;
  Promise.rejectDelay &#x3D; function (reason, time) &amp;#123;
    &#x2F;&#x2F; 返回一个失败的promise
    return new Promise((resolve, reject) &#x3D;&gt; &amp;#123;
      setTimeout(() &#x3D;&gt; &amp;#123;
        reject(reason)
      &amp;#125;, time)
    &amp;#125;)
  &amp;#125;

  &#x2F;&#x2F; 向外暴露Promise函数
  window.Promise &#x3D; Promise
&amp;#125;)(window)

</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#null"><span class="nav-number">1.6.1.</span> <span class="nav-text">part1.错误的类型</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#null"><span class="nav-number">1.6.2.</span> <span class="nav-text">part2.错误处理</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#null"><span class="nav-number">1.6.3.</span> <span class="nav-text">part3.error对象的结构</span></a></li></ol></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#null"><span class="nav-number"></span> <span class="nav-text">Promise的理解与使用

1.抽象表达：Promise是js中进行异步编程的新的解决方案（避免了以往的纯异步嵌套回调）

2.具体表达：(1) 从语法上来说：Promise是一个构造函数

(2) 从功能上来说：Promise对象用来封装一个异步操作并可以获取其结果

promise的状态1.pending(等待状态)

2.resolved(解决状态)

3.rejected(拒接状态)

其中转变只可由:

1.pending转为resolved

2.pending转为rejected

且一个promise只可转变一次

Promise的基本使用1
2
3
4
5
6
7
8
9
10
11
12
13
&#x2F;&#x2F;创建Promise对象
const p&#x3D;new Promise((resolve,reject)&#x3D;&gt;&amp;#123;
    &#x2F;&#x2F;执行异步操作
    setTimeout(()&#x3D;&gt;&amp;#123;
        resolve(&quot;成功了&quot;)&#x2F;&#x2F;成功时调用
        &#x2F;&#x2F;reject(&quot;失败了&quot;)&#x2F;&#x2F;失败是调用
    &amp;#125;)
&amp;#125;)
&#x2F;&#x2F;通过promise的then()指定成功和失败的回调函数
p.then(
    value &#x3D;&gt; console.log(value),&#x2F;&#x2F;成功了
    reason &#x3D;&gt; console.log(reason)&#x2F;&#x2F;失败了
)

为什么要用Promise1.指定回调函数的方式更灵活传统必须在启动任务前指定回调

而promise先启动异步任务&#x3D;&gt;返回promise对象&#x3D;&gt;给promise对象绑定回调函数(甚至可以在异步任务结束后指定)
2.支持链式调用，可以解决回调地狱问题回调地狱：回调函数嵌套调用，外部回调函数异步执行的结果是嵌套的回调执行的条件，这样就造成不便于阅读、不便于异常处理
promise所支持的链式调用可以解决这个方案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
&#x2F;&#x2F;成功的回调
function successCallback(result) &amp;#123;
    console.log(&quot;成功了&quot;)
&amp;#125;
&#x2F;&#x2F;失败的回调
function failureCallback(error) &amp;#123;
    console.log(&quot;失败了&quot;)
&amp;#125;
&#x2F;&#x2F;使用纯回调函数
createAudioFileAsync(audio,successCallback,failureCallback)
&#x2F;* 1.2. 使用 Promise *&#x2F;
const promise &#x3D; createAudioFileAsync(audio);
    setTimeout(() &#x3D;&gt; &amp;#123; 
        promise.then(successCallback, failureCallback); 
    &amp;#125;, 3000)
&#x2F;&#x2F;回调地狱
 doSomething(function(result) &amp;#123; 
     doSomethingElse(result, function(newResult) &amp;#123;
         doThirdThing(newResult, function(finalResult) &amp;#123;
             console.log(&#39;Got the final result: &#39; + finalResult) 
             &amp;#125;, failureCallback) 
            &amp;#125;, failureCallback) 
        &amp;#125;, failureCallback)
 &#x2F;* 
2.2. 使用promise的链式调用解决回调地狱
*&#x2F;
doSomething()
.then(function(result) &amp;#123;
  return doSomethingElse(result)
&amp;#125;)
.then(function(newResult) &amp;#123;
  return doThirdThing(newResult)
&amp;#125;)
.then(function(finalResult) &amp;#123;
  console.log(&#39;Got the final result: &#39; + finalResult)
&amp;#125;)
.catch(failureCallback)
&#x2F;* 
2.3. async&#x2F;await: 回调地狱的终极解决方案
*&#x2F;
async function request() &amp;#123;
  try &amp;#123;
    const result &#x3D; await doSomething()
    const newResult &#x3D; await doSomethingElse(result)
    const finalResult &#x3D; await doThirdThing(newResult)
    console.log(&#39;Got the final result: &#39; + finalResult)
  &amp;#125; catch (error) &amp;#123;
    failureCallback(error)
  &amp;#125;

PromiseAPI1. Promise构造函数: Promise (excutor) {}
    excutor函数: 同步执行  (resolve, reject) &#x3D;&gt; {}
    resolve函数: 内部定义成功时我们调用的函数 value &#x3D;&gt; {}
    reject函数: 内部定义失败时我们调用的函数 reason &#x3D;&gt; {}
    说明: excutor会在Promise内部立即同步回调,异步操作在执行器中执行

2. Promise.prototype.then方法: (onResolved, onRejected) &#x3D;&gt; {}
    onResolved函数: 成功的回调函数  (value) &#x3D;&gt; {}
    onRejected函数: 失败的回调函数 (reason) &#x3D;&gt; {}
    说明: 指定用于得到成功value的成功回调和用于得到失败reason的失败回调
          返回一个新的promise对象

3. Promise.prototype.catch方法: (onRejected) &#x3D;&gt; {}
    onRejected函数: 失败的回调函数 (reason) &#x3D;&gt; {}
    说明: then()的语法糖, 相当于: then(undefined, onRejected)

4. Promise.resolve方法: (value) &#x3D;&gt; {}
    value: 成功的数据或promise对象
    说明: 返回一个成功&#x2F;失败的promise对象

5. Promise.reject方法: (reason) &#x3D;&gt; {}
    reason: 失败的原因
    说明: 返回一个失败的promise对象

6. Promise.all方法: (promises) &#x3D;&gt; {}
    promises: 包含n个promise的数组
    说明: 返回一个新的promise, 只有所有的promise都成功才成功, 只要有一个失败了就直接失败
7. Promise.race方法: (promises) &#x3D;&gt; {}
    promises: 包含n个promise的数组
    说明: 返回一个新的promise, 第一个完成的promise的结果状态就是最终的结果状态Promise的相关问题1.如何改变promise的状态?
  (1)resolve(value): 如果当前是pendding就会变为resolved
  (2)reject(reason): 如果当前是pendding就会变为rejected
  (3)抛出异常: 如果当前是pendding就会变为rejected

2.    一个promise指定多个成功&#x2F;失败回调函数, 都会调用吗?
  当promise改变为对应状态时都会调用1
2
3
4
5
6
7
8
9
10
11
12
13
const p&#x3D;new Promise((resolve,reject)&#x3D;&gt;&amp;#123;
    resolve(1)
    &#x2F;&#x2F;theow 3
&amp;#125;)
&#x2F;&#x2F;下面这两个then均会调用
 p.then(
      value &#x3D;&gt; &amp;#123;&amp;#125;,
      reason &#x3D;&gt; &amp;#123;console.log(&#39;reason&#39;, reason)&amp;#125;
    )
p.then(
      value &#x3D;&gt; &amp;#123;&amp;#125;,
      reason &#x3D;&gt; &amp;#123;console.log(&#39;reason2&#39;, reason)&amp;#125;
    )

 3.改变promise状态和指定回调函数谁先谁后?
  (1)都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
  (2)如何先改状态再指定回调?
    ①在执行器中直接调用resolve()&#x2F;reject()
    ②延迟更长时间才调用then()
  (3)什么时候才能得到数据?
    ①如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
    ②如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据

4.promise.then()返回的新promise的结果状态由什么决定?
  (1)简单表达: 由then()指定的回调函数执行的结果决定
  (2)详细表达:
      ①如果抛出异常, 新promise变为rejected, reason为抛出的异常
      ②如果返回的是非promise的任意值, 新promise变为resolved, value为返回的值
      ③如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果 
5.promise如何串连多个操作任务?
  (1)promise的then()返回一个新的promise, 可以开成then()的链式调用
  (2)通过then的链式调用串连多个同步&#x2F;异步任务
6.promise异常传&#x2F;穿透?
  (1)当使用promise的then链式调用时, 可以在最后指定失败的回调, 
  (2)前面任何操作出了异常, 都会传到最后失败的回调中处理
7.中断promise链?
  (1)当使用promise的then链式调用时, 在中间中断, 不再调用后面的回调函数
  (2)办法: 在回调函数中返回一个pendding状态的promise对象
    new Promise(() &#x3D;&gt; {}) 返回一个pending的promise  中断promise链1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
&#x2F;* 
自定义Promise函数模块: IIFE
*&#x2F;
(function (window) &amp;#123;

  const PENDING &#x3D; &#39;pending&#39;
  const RESOLVED &#x3D; &#39;resolved&#39;
  const REJECTED &#x3D; &#39;rejected&#39;
  
  &#x2F;* 
  Promise构造函数
  excutor: 执行器函数(同步执行)
  *&#x2F;
  function Promise(excutor) &amp;#123;
    &#x2F;&#x2F; 将当前promise对象保存起来
    const self &#x3D; this
    self.status &#x3D; PENDING &#x2F;&#x2F; 给promise对象指定status属性, 初始值为pending
    self.data &#x3D; undefined &#x2F;&#x2F; 给promise对象指定一个用于存储结果数据的属性
    self.callbacks &#x3D; [] &#x2F;&#x2F; 每个元素的结构: &amp;#123; onResolved() &amp;#123;&amp;#125;, onRejected() &amp;#123;&amp;#125;&amp;#125;

    function resolve (value) &amp;#123;
      &#x2F;&#x2F; 如果当前状态不是pending, 直接结束
      if (self.status!&#x3D;&#x3D;PENDING) &amp;#123;
        return
      &amp;#125;

      &#x2F;&#x2F; 将状态改为resolved
      self.status &#x3D; RESOLVED
      &#x2F;&#x2F; 保存value数据
      self.data &#x3D; value
      &#x2F;&#x2F; 如果有待执行callback函数, 立即异步执行回调函数onResolved
      if (self.callbacks.length&gt;0) &amp;#123;
        setTimeout(() &#x3D;&gt; &amp;#123; &#x2F;&#x2F; 放入队列中执行所有成功的回调
          self.callbacks.forEach(calbacksObj &#x3D;&gt; &amp;#123;
            calbacksObj.onResolved(value)
          &amp;#125;) 
        &amp;#125;);
      &amp;#125;

    &amp;#125;

    function reject (reason) &amp;#123;
      &#x2F;&#x2F; 如果当前状态不是pending, 直接结束
      if (self.status!&#x3D;&#x3D;PENDING) &amp;#123;
        return
      &amp;#125;

      &#x2F;&#x2F; 将状态改为rejected
      self.status &#x3D; REJECTED
      &#x2F;&#x2F; 保存value数据
      self.data &#x3D; reason
      &#x2F;&#x2F; 如果有待执行callback函数, 立即异步执行回调函数onRejected
      if (self.callbacks.length&gt;0) &amp;#123;
        setTimeout(() &#x3D;&gt; &amp;#123; &#x2F;&#x2F; 放入队列中执行所有成功的回调
          self.callbacks.forEach(calbacksObj &#x3D;&gt; &amp;#123;
            calbacksObj.onRejected(reason)
          &amp;#125;) 
        &amp;#125;);
      &amp;#125;
    &amp;#125;
    
    &#x2F;&#x2F; 立即同步执行excutor
    try &amp;#123;
      excutor(resolve, reject)
    &amp;#125; catch (error) &amp;#123; &#x2F;&#x2F; 如果执行器抛出异常, promise对象变为rejected状态
      reject(error)
    &amp;#125;
    
  &amp;#125;

  &#x2F;* 
  Promise原型对象的then()
  指定成功和失败的回调函数
  返回一个新的promise对象
  返回promise的结果由onResolved&#x2F;onRejected执行结果决定

  *&#x2F;
  Promise.prototype.then &#x3D; function (onResolved, onRejected) &amp;#123;
    const self &#x3D; this

    &#x2F;&#x2F; 指定回调函数的默认值(必须是函数)
    onResolved &#x3D; typeof onResolved&#x3D;&#x3D;&#x3D;&#39;function&#39; ? onResolved : value &#x3D;&gt; value
    onRejected &#x3D; typeof onRejected&#x3D;&#x3D;&#x3D;&#39;function&#39; ? onRejected : reason &#x3D;&gt; &amp;#123;throw reason&amp;#125;


    &#x2F;&#x2F; 返回一个新的promise
    return new Promise((resolve, reject) &#x3D;&gt; &amp;#123;

      &#x2F;* 
      执行指定的回调函数
      根据执行的结果改变return的promise的状态&#x2F;数据
      *&#x2F;
      function handle(callback) &amp;#123;
        &#x2F;* 
        返回promise的结果由onResolved&#x2F;onRejected执行结果决定
        1. 抛出异常, 返回promise的结果为失败, reason为异常
        2. 返回的是promise, 返回promise的结果就是这个结果
        3. 返回的不是promise, 返回promise为成功, value就是返回值
        *&#x2F;
        try &amp;#123;
          const result &#x3D; callback(self.data)
          if (result instanceof Promise) &amp;#123; &#x2F;&#x2F; 2. 返回的是promise, 返回promise的结果就是这个结果
            &#x2F;* 
            result.then(
              value &#x3D;&gt; resolve(vlaue),
              reason &#x3D;&gt; reject(reason)
            ) *&#x2F;
            result.then(resolve, reject)
          &amp;#125; else &amp;#123; &#x2F;&#x2F; 3. 返回的不是promise, 返回promise为成功, value就是返回值
            resolve(result)
          &amp;#125;

        &amp;#125; catch (error) &amp;#123; &#x2F;&#x2F; 1. 抛出异常, 返回promise的结果为失败, reason为异常
          reject(error)
        &amp;#125;
      &amp;#125;

      &#x2F;&#x2F; 当前promise的状态是resolved
      if (self.status&#x3D;&#x3D;&#x3D;RESOLVED) &amp;#123;
        &#x2F;&#x2F; 立即异步执行成功的回调函数
        setTimeout(() &#x3D;&gt; &amp;#123;
          handle(onResolved)
        &amp;#125;)
      &amp;#125; else if (self.status&#x3D;&#x3D;&#x3D;REJECTED) &amp;#123; &#x2F;&#x2F; 当前promise的状态是rejected
        &#x2F;&#x2F; 立即异步执行失败的回调函数
        setTimeout(() &#x3D;&gt; &amp;#123;
          handle(onRejected)
        &amp;#125;)
      &amp;#125; else &amp;#123; &#x2F;&#x2F; 当前promise的状态是pending
        &#x2F;&#x2F; 将成功和失败的回调函数保存callbacks容器中缓存起来
        self.callbacks.push(&amp;#123;
          onResolved (value) &amp;#123;
            handle(onResolved)
          &amp;#125;,
          onRejected (reason) &amp;#123;
            handle(onRejected)
          &amp;#125;
        &amp;#125;)
      &amp;#125;
    &amp;#125;)
  &amp;#125;
&#x2F;* 
  function fn(event) &amp;#123;
    
  &amp;#125;
  div.onclick &#x3D; function (event)&amp;#123;
    fn(event)
  &amp;#125;
  div.onclick &#x3D; fn
 *&#x2F;
  &#x2F;* 
  Promise原型对象的catch()
  指定失败的回调函数
  返回一个新的promise对象
  *&#x2F;
  Promise.prototype.catch &#x3D; function (onRejected) &amp;#123;
    return this.then(undefined, onRejected)
  &amp;#125;

  &#x2F;* 
  Promise函数对象的resolve方法
  返回一个指定结果的成功的promise
  *&#x2F;
  Promise.resolve &#x3D; function (value) &amp;#123;
    &#x2F;&#x2F; 返回一个成功&#x2F;失败的promise
    return new Promise((resolve, reject) &#x3D;&gt; &amp;#123;
      &#x2F;&#x2F; value是promise
      if (value instanceof Promise) &amp;#123; &#x2F;&#x2F; 使用value的结果作为promise的结果
        value.then(resolve, reject)
      &amp;#125; else &amp;#123; &#x2F;&#x2F; value不是promise  &#x3D;&gt; promise变为成功, 数据是value
        resolve(value)
      &amp;#125;
    &amp;#125;)
  &amp;#125;

  &#x2F;* 
  Promise函数对象的reject方法
  返回一个指定reason的失败的promise
  *&#x2F;
  Promise.reject &#x3D; function (reason) &amp;#123;
    &#x2F;&#x2F; 返回一个失败的promise
    return new Promise((resolve, reject) &#x3D;&gt; &amp;#123;
      reject(reason)
    &amp;#125;)
  &amp;#125;

  &#x2F;* 
  Promise函数对象的all方法
  返回一个promise, 只有当所有proimse都成功时才成功, 否则只要有一个失败的就失败
  *&#x2F;
  Promise.all &#x3D; function (promises) &amp;#123;
    &#x2F;&#x2F; 用来保存所有成功value的数组
    const values &#x3D; new Array(promises.length) 
    &#x2F;&#x2F; 用来保存成功promise的数量
    let resolvedCount &#x3D; 0
    &#x2F;&#x2F; 返回一个新的promise
    return new Promise((resolve, reject) &#x3D;&gt; &amp;#123;
      &#x2F;&#x2F; 遍历promises获取每个promise的结果
      promises.forEach((p, index) &#x3D;&gt; &amp;#123;
        Promise.resolve(p).then(
          value &#x3D;&gt; &amp;#123;
            resolvedCount++ &#x2F;&#x2F; 成功的数量加1
            &#x2F;&#x2F; p成功, 将成功的vlaue保存vlaues
            &#x2F;&#x2F; values.push(value)
            values[index] &#x3D; value

            &#x2F;&#x2F; 如果全部成功了, 将return的promise改变成功
            if (resolvedCount&#x3D;&#x3D;&#x3D;promises.length) &amp;#123;
              resolve(values)
            &amp;#125;

          &amp;#125;,
          reason &#x3D;&gt; &amp;#123; &#x2F;&#x2F; 只要一个失败了, return的promise就失败
            reject(reason)
          &amp;#125;
        )
      &amp;#125;)
    &amp;#125;)
  &amp;#125;

  &#x2F;* 
  Promise函数对象的race方法
  返回一个promise, 其结果由第一个完成的promise决定
  *&#x2F;
  Promise.race &#x3D; function (promises) &amp;#123;
    &#x2F;&#x2F; 返回一个promise
    return new Promise((resolve, reject) &#x3D;&gt; &amp;#123;
      &#x2F;&#x2F; 遍历promises获取每个promise的结果
      promises.forEach((p, index) &#x3D;&gt; &amp;#123;
        Promise.resolve(p).then(
          value &#x3D;&gt; &amp;#123;&#x2F;&#x2F; 一旦有成功了, 将return变为成功
            resolve(value)
          &amp;#125;,
          reason &#x3D;&gt; &amp;#123; &#x2F;&#x2F; 一旦有失败了, 将return变为失败
            reject(reason)
          &amp;#125;
        )
      &amp;#125;)
    &amp;#125;)
  &amp;#125;

  &#x2F;* 
  返回一个promise对象, 它在指定的时间后才确定结果
  *&#x2F;
  Promise.resolveDelay &#x3D; function (value, time) &amp;#123;
    &#x2F;&#x2F; 返回一个成功&#x2F;失败的promise
    return new Promise((resolve, reject) &#x3D;&gt; &amp;#123;
      setTimeout(() &#x3D;&gt; &amp;#123;
        &#x2F;&#x2F; value是promise
        if (value instanceof Promise) &amp;#123; &#x2F;&#x2F; 使用value的结果作为promise的结果
          value.then(resolve, reject)
        &amp;#125; else &amp;#123; &#x2F;&#x2F; value不是promise  &#x3D;&gt; promise变为成功, 数据是value
          resolve(value)
        &amp;#125;
      &amp;#125;, time)
    &amp;#125;)
  &amp;#125;

  &#x2F;* 
  返回一个promise对象, 它在指定的时间后才失败
  *&#x2F;
  Promise.rejectDelay &#x3D; function (reason, time) &amp;#123;
    &#x2F;&#x2F; 返回一个失败的promise
    return new Promise((resolve, reject) &#x3D;&gt; &amp;#123;
      setTimeout(() &#x3D;&gt; &amp;#123;
        reject(reason)
      &amp;#125;, time)
    &amp;#125;)
  &amp;#125;

  &#x2F;&#x2F; 向外暴露Promise函数
  window.Promise &#x3D; Promise
&amp;#125;)(window)

</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-抽象表达："><span class="nav-number">0.1.</span> <span class="nav-text">1.抽象表达：</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-具体表达："><span class="nav-number">0.2.</span> <span class="nav-text">2.具体表达：</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#promise的状态"><span class="nav-number">0.3.</span> <span class="nav-text">promise的状态</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Promise的基本使用"><span class="nav-number">0.4.</span> <span class="nav-text">Promise的基本使用</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#为什么要用Promise"><span class="nav-number">0.5.</span> <span class="nav-text">为什么要用Promise</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#1-指定回调函数的方式更灵活"><span class="nav-number">0.5.1.</span> <span class="nav-text">1.指定回调函数的方式更灵活</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-支持链式调用，可以解决回调地狱问题"><span class="nav-number">0.5.2.</span> <span class="nav-text">2.支持链式调用，可以解决回调地狱问题</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#PromiseAPI"><span class="nav-number">0.6.</span> <span class="nav-text">PromiseAPI</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Promise的相关问题"><span class="nav-number">0.7.</span> <span class="nav-text">Promise的相关问题</span></a></li></ol></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2020</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">LiangJH</span>

  
</div>


  <div class="powered-by">由 <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a> 强力驱动</div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">主题 &mdash; <a class="theme-link" target="_blank" href="https://github.com/iissnan/hexo-theme-next">NexT.Pisces</a> v5.1.4</div>




        







        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  
    <script type="text/javascript" src="/Liang34/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/Liang34/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
  

  
  
    <script type="text/javascript" src="/Liang34/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
  

  
  
    <script type="text/javascript" src="/Liang34/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/Liang34/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/Liang34/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
  


  


  <script type="text/javascript" src="/Liang34/js/src/utils.js?v=5.1.4"></script>

  <script type="text/javascript" src="/Liang34/js/src/motion.js?v=5.1.4"></script>



  
  


  <script type="text/javascript" src="/Liang34/js/src/affix.js?v=5.1.4"></script>

  <script type="text/javascript" src="/Liang34/js/src/schemes/pisces.js?v=5.1.4"></script>



  
  <script type="text/javascript" src="/Liang34/js/src/scrollspy.js?v=5.1.4"></script>
<script type="text/javascript" src="/Liang34/js/src/post-details.js?v=5.1.4"></script>



  


  <script type="text/javascript" src="/Liang34/js/src/bootstrap.js?v=5.1.4"></script>



  


  




	





  





  












  





  

  

  

  
  

  

  

  

<script src="/Liang34/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script><script>L2Dwidget.init({"pluginRootPath":"live2dw/","pluginJsPath":"lib/","pluginModelPath":"assets/","tagMode":false,"debug":false,"model":{"jsonPath":"/Liang34/live2dw/assets/hibiki.model.json"},"display":{"position":"right","width":145,"height":315},"mobile":{"show":true,"scale":0.5},"react":{"opacityDefault":0.7,"opacityOnHover":0.8},"log":false});</script></body>
</html>
